#ifndef PACKET_H_
        #include "Packet.h"
#endif

//-----------------------------------------------------------------------------

// Ctor
PacketBuilder::PacketBuilder()
{
    Clear();
}

//-----------------------------------------------------------------------------

// Dtor
PacketBuilder::~PacketBuilder()
{
}

//-----------------------------------------------------------------------------

// Clear the packet data
void PacketBuilder::Clear()
{
        // Clear out the data
        memset(data, 0, 8192);
        size = 6;
}

//-----------------------------------------------------------------------------

// Get the packet buffer
tPacket * PacketBuilder::GetPacket()
{
        return (tPacket *)data;
}

//-----------------------------------------------------------------------------

// Return the packet size
WORD PacketBuilder::GetSize()
{
        return size;
}

//-----------------------------------------------------------------------------

// Set the packet's opcode
void PacketBuilder::SetOpcode(WORD opcode)
{
        Clear();

        LPWORD stream = (LPWORD)data;
        stream++;
        (*stream) = opcode;
}

//-----------------------------------------------------------------------------

// Add data function
void PacketBuilder::AppendByte(BYTE byte)
{
        LPBYTE stream = (LPBYTE)data;
        stream += size;
        (*stream) = byte;
        ++size;
        WORD tmpSize = size - 6;
        memcpy(data, &tmpSize, 2);
}

//-----------------------------------------------------------------------------

// Add data function
void PacketBuilder::AppendWord(WORD word)
{
        LPBYTE stream = (LPBYTE)data;
        stream += size;
        (*(LPWORD)stream) = word;
        size += 2;
        WORD tmpSize = size - 6;
        memcpy(data, &tmpSize, 2);
}

//-----------------------------------------------------------------------------

// Add data function
void PacketBuilder::AppendDword(DWORD dword)
{
        LPBYTE stream = (LPBYTE)data;
        stream += size;
        (*(LPDWORD)stream) = dword;
        size += 4;
        WORD tmpSize = size - 6;
        memcpy(data, &tmpSize, 2);
}

//-----------------------------------------------------------------------------

// Append a string
void PacketBuilder::AppendString(const char * str)
{
        LPBYTE stream = (LPBYTE)data;
        stream += size;
        memcpy(stream, str, strlen(str));
        size += (WORD)strlen(str);
        WORD tmpSize = size - 6;
        memcpy(data, &tmpSize, 2);
}

//-----------------------------------------------------------------------------

// Append a string
void PacketBuilder::AppendWideString(const wchar_t * str)
{
        static int constSize = sizeof(wchar_t);
        LPBYTE stream = (LPBYTE)data;
        stream += size;
        memcpy(stream, str, constSize * wcslen(str));
        size += (WORD)(constSize * wcslen(str));
        WORD tmpSize = size - 6;
        memcpy(data, &tmpSize, 2);
}

//-----------------------------------------------------------------------------

// Append a string
void PacketBuilder::AppendArray(int length, void * buffer)
{
        LPBYTE stream = (LPBYTE)data;
        stream += size;
        memcpy((char*)stream, buffer, length);
        size += length;
        WORD tmpSize = size - 6;
        memcpy(data, &tmpSize, 2);
}

//-----------------------------------------------------------------------------

// Append a double
void PacketBuilder::AppendDouble(double value)
{
        static int constSize = sizeof(double);
        LPBYTE stream = (LPBYTE)data;
        stream += size;
        (*(double*)stream) = value;
        size += constSize;
        WORD tmpSize = size - 6;
        memcpy(data, &tmpSize, 2);
}

//-----------------------------------------------------------------------------

// Append a float
void PacketBuilder::AppendFloat(float value)
{
        static int constSize = sizeof(float);
        LPBYTE stream = (LPBYTE)data;
        stream += size;
        (*(float*)stream) = value;
        size += constSize;
        WORD tmpSize = size - 6;
        memcpy(data, &tmpSize, 2);
}

//-----------------------------------------------------------------------------

// Copy this packet into the buffer
void PacketBuilder::Copy(tPacket * outPacket)
{
        memcpy(outPacket, data, size);
}

//-----------------------------------------------------------------------------

// Ctor
PacketReader::PacketReader()
{
        packet = 0;
        index = 0;
}

//-----------------------------------------------------------------------------

PacketReader::~PacketReader()
{
}

//-----------------------------------------------------------------------------

// Ctor - build from a packet
PacketReader::PacketReader(tPacket * p)
{
        SetPacket(p);
}

//-----------------------------------------------------------------------------

// Set a packet for the object
void PacketReader::SetPacket(tPacket * p)
{
        packet = p;
        index = 0;
}

//-----------------------------------------------------------------------------

// Returns the packet opcode
WORD PacketReader::GetPacketOpcode()
{
        return packet->opcode;
}

//-----------------------------------------------------------------------------

// Returns how much data can be read from the packet
int PacketReader::GetBytesLeft()
{
        if(index < packet->size)
                return packet->size - index;
        return 0;
}

//-----------------------------------------------------------------------------

// Returns the packet's size
WORD PacketReader::GetPacketSize()
{
        return packet->size;
}

//-----------------------------------------------------------------------------

// Read in specific data types
BYTE PacketReader::ReadByte()
{
        static int constSize = sizeof(BYTE);
        if(index + constSize > packet->size) return 0;
        LPBYTE stream = packet->data;
        stream += index;
        index += constSize;
        return (*stream);
}

//-----------------------------------------------------------------------------

// Read in specific data types
WORD PacketReader::ReadWord()
{
        static int constSize = sizeof(WORD);
        if(index + constSize > packet->size) return 0;
        LPBYTE stream = packet->data;
        stream += index;
        index += constSize;
        return *((LPWORD)(stream));
}

//-----------------------------------------------------------------------------

// Read in specific data types
DWORD PacketReader::ReadDword()
{
        static int constSize = sizeof(DWORD);
        if(index + constSize > packet->size) return 0;
        LPBYTE stream = packet->data;
        stream += index;
        index += constSize;
        return *((LPDWORD)(stream));
}

//-----------------------------------------------------------------------------

// Read in specific data types
int PacketReader::ReadInt()
{
        static int constSize = sizeof(int);
        if(index + constSize > packet->size) return 0;
        LPBYTE stream = packet->data;
        stream += index;
        index += constSize;
        return *((LPDWORD)(stream));
}

//-----------------------------------------------------------------------------

// Read in specific data types
void PacketReader::ReadString(int size, char * outBuffer)
{
        if(index + size > packet->size) return;
        LPBYTE stream = packet->data;
        stream += index;
        index += size;
        memcpy(outBuffer, stream, size);
        outBuffer[size] = 0;
}

//-----------------------------------------------------------------------------

// Read in specific data types
void PacketReader::ReadWideString(int size, wchar_t * outBuffer)
{
        static int constSize = sizeof(wchar_t);
        if(index + (size * constSize) > packet->size) return;
        LPBYTE stream = packet->data;
        stream += index;
        index += (size * constSize);
        memcpy(outBuffer, stream, size * constSize);
        outBuffer[size * constSize] = 0;
}

//-----------------------------------------------------------------------------

// Read in specific data types
float PacketReader::ReadFloat()
{
        static int constSize = sizeof(float);
        if(index + constSize > packet->size) return 0;
        LPBYTE stream = packet->data;
        stream += index;
        index += constSize;
        return *((float*)(stream));
}

//-----------------------------------------------------------------------------

// Read in specific data types
double PacketReader::ReadDouble()
{
        static int constSize = sizeof(double);
        if(index + constSize > packet->size) return 0;
        LPBYTE stream = packet->data;
        stream += index;
        index += constSize;
        return *((double*)(stream));
}

//-----------------------------------------------------------------------------

// Read in specific data types
__int64 PacketReader::Read64()
{
        static int constSize = sizeof(__int64);
        if(index + constSize > packet->size) return 0;
        LPBYTE stream = packet->data;
        stream += index;
        index += constSize;
        return *((__int64*)(stream));
}

//-----------------------------------------------------------------------------

// Read in specific data types
void PacketReader::ReadArray(int size, void * outBuffer)
{
        if(index + size > packet->size) return;
        LPBYTE stream = packet->data;
        stream += index;
        index += size;
        memcpy(outBuffer, stream, size);
}

//-----------------------------------------------------------------------------

// Returns the packet associated with this reader
tPacket * PacketReader::GetPacket()
{
        return packet;
}

//-----------------------------------------------------------------------------

// Returns the current index the reader is at
DWORD PacketReader::GetIndex()
{
        return index;
}

//-----------------------------------------------------------------------------
